import type { AppConfig } from '@shared/types/'
import { ipcMain } from 'electron'
// 简易并发控制器，避免额外依赖带来的构建问题
import { getConfig, updateConfig } from '../config/index'
import { getLogger } from '../logger/index'

/**
 * 验证结果项
 *
 * @description 验证结果项，包括服务器、提供商ID、是否成功、状态、错误信息
 */
interface ValidateResultItem {
  server: string
  providerId?: string
  ok: boolean
  status?: number
  error?: string
}

/**
 * 解析代理条目
 *
 * @description 解析代理条目，包括服务器、认证信息
 *
 * @param {string} entry - 代理条目字符串
 * @param {object} fallbackAuth - 备用认证信息
 * @param {string} protocol - 协议
 * @returns {object} 解析结果
 */
function parseProxyEntry(entry: string, fallbackAuth?: { username: string, password: string }, protocol = 'http'): { server: string, auth?: { username: string, password: string } } {
  const parts = String(entry || '').split(':')
  if (parts.length >= 4) {
    const host = parts[0]
    const port = parts[1]
    const username = parts[2]
    const password = parts.slice(3).join(':')
    return { server: `${protocol}://${host}:${port}`, auth: { username, password } }
  }
  return { server: `${protocol}://${entry}`, auth: fallbackAuth }
}

/**
 * 设置代理处理器
 *
 * @description 设置代理处理器，包括验证、列表、清除等操作
 */
export function setupProxyHandlers(): void {
  const logger = getLogger()

  // 手动校验：聚合所有启用的代理池，检查连通性并按结果更新临时黑名单
  ipcMain.handle('proxy:validate-pool', async () => {
    const cfg = getConfig()
    const entries = buildProxyEntries(cfg)
    const results: ValidateResultItem[] = []

    // 简易并发执行（并发=2）
    const concurrency = 2
    let index = 0
    const workers: Promise<void>[] = []
    const runNext = async () => {
      const i = index++
      const entry = entries[i]
      if (!entry)
        return
      try {
        const r = await validateSingle(entry.server, entry.auth?.username, entry.auth?.password, cfg.proxy.validation)
        results.push({ server: entry.server, providerId: entry.providerId, ...r })
      }
      catch (err: any) {
        results.push({ server: entry.server, providerId: entry.providerId, ok: false, error: String(err?.message || err) })
      }
      await runNext()
    }

    const ttlMinutes = cfg.proxy.blacklist_ttl_minutes ?? 60
    const ttlMs = Math.max(1, ttlMinutes) * 60 * 1000
    const now = Date.now()

    for (let w = 0; w < Math.min(concurrency, entries.length); w++)
      workers.push(runNext())
    await Promise.all(workers)

    // 更新临时黑名单：失败的加入/刷新 until；成功的从黑名单中移除
    const blacklist = Array.isArray(cfg.proxy.temp_blacklist) ? cfg.proxy.temp_blacklist.slice() : []
    const byServer = new Map<string, number>()
    blacklist.forEach((b, i) => byServer.set(b.server, i))

    for (const r of results) {
      if (!r.ok) {
        const until = now + ttlMs
        const idx = byServer.get(r.server)
        if (idx !== undefined) {
          blacklist[idx] = { ...blacklist[idx], until, lastCheckedAt: now, reason: r.error || `status:${r.status || 0}` }
        }
        else {
          blacklist.push({ server: r.server, until, lastCheckedAt: now, reason: r.error || `status:${r.status || 0}` })
        }
      }
      else {
        const idx = byServer.get(r.server)
        if (idx !== undefined) {
          blacklist.splice(idx, 1)
          byServer.delete(r.server)
        }
      }
    }

    // 清理过期项
    const pruned = blacklist.filter(b => b.until > now)

    await updateConfig({ proxy: { temp_blacklist: pruned } as any })

    logger.info('✅ 代理池校验完成', {
      total: results.length,
      ok: results.filter(r => r.ok).length,
      failed: results.filter(r => !r.ok).length,
    })

    return {
      success: true,
      total: results.length,
      ok: results.filter(r => r.ok).length,
      failed: results.filter(r => !r.ok).length,
      results,
      blacklist: pruned,
    }
  })

  // 列出临时黑名单（自动清理过期）
  ipcMain.handle('proxy:blacklist:list', async () => {
    const cfg = getConfig()
    const now = Date.now()
    const list = (cfg.proxy.temp_blacklist || []).filter(b => b.until > now)
    if (list.length !== (cfg.proxy.temp_blacklist || []).length) {
      await updateConfig({ proxy: { temp_blacklist: list } as any })
    }
    return { success: true, list }
  })

  // 清空临时黑名单
  ipcMain.handle('proxy:blacklist:clear', async () => {
    await updateConfig({ proxy: { temp_blacklist: [] } as any })
    return { success: true }
  })

  // ====== 月度流量超额标记 ======
  // 列出（当前有效月）超额标记
  ipcMain.handle('proxy:quota:list', async () => {
    const cfg = getConfig()
    const list = Array.isArray((cfg as any)?.proxy?.quota_exceeded) ? (cfg as any).proxy.quota_exceeded : []
    return { success: true, list }
  })

  // 标记某 provider 本月为超额
  ipcMain.handle('proxy:quota:mark', async (_e, { provider_id, reason }: { provider_id: string, reason?: string }) => {
    const cfg = getConfig()
    const prev = Array.isArray((cfg as any)?.proxy?.quota_exceeded) ? (cfg as any).proxy.quota_exceeded : []
    const now = new Date()
    const month = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`
    const next = prev.filter((q: any) => !(q && q.provider_id === provider_id && q.month === month))
    next.push({ provider_id, month, reason, marked_at: Date.now() })
    await updateConfig({ proxy: { quota_exceeded: next } as any })
    logger.info('✅ 标记代理提供商为本月超额', { provider_id, month, reason })
    return { success: true }
  })

  // 清除某 provider 的超额标记（可选按月，不传则清当前月）
  ipcMain.handle('proxy:quota:clear', async (_e, { provider_id, month }: { provider_id: string, month?: string }) => {
    const cfg = getConfig()
    const prev = Array.isArray((cfg as any)?.proxy?.quota_exceeded) ? (cfg as any).proxy.quota_exceeded : []
    const targetMonth = month || (() => {
      const d = new Date()
      return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`
    })()
    const next = prev.filter((q: any) => !(q && q.provider_id === provider_id && q.month === targetMonth))
    await updateConfig({ proxy: { quota_exceeded: next } as any })
    logger.info('✅ 清除代理提供商本月超额标记', { provider_id, month: targetMonth })
    return { success: true }
  })

  // ====== WebShare 统计：查询订阅期聚合用量（用于辅助判定是否超额） ======
  ipcMain.handle('proxy:webshare:stats-aggregate', async (_e, { provider_id, plan_id, gte, lte }: { provider_id: string, plan_id?: string, gte?: string, lte?: string }) => {
    const cfg = getConfig()
    const providers = Array.isArray(cfg.proxy?.providers) ? cfg.proxy.providers : []
    const p = providers.find(pp => pp && (pp.id === provider_id)) as any
    if (!p)
      return { success: false, error: `provider ${provider_id} not found` }
    if (!p.api_key)
      return { success: false, error: 'missing api_key' }

    const qs: string[] = []
    if (plan_id)
      qs.push(`plan_id=${encodeURIComponent(String(plan_id))}`)
    if (gte)
      qs.push(`timestamp__gte=${encodeURIComponent(gte)}`)
    if (lte)
      qs.push(`timestamp__lte=${encodeURIComponent(lte)}`)
    const url = `https://proxy.webshare.io/api/v2/stats/aggregate/${qs.length ? `?${qs.join('&')}` : ''}`

    // 直接请求（无需走代理）
    const res = await fetch(url, {
      headers: { Authorization: `Token ${p.api_key}` },
    }).catch((e: any) => Promise.reject(new Error(`WebShare stats 请求失败: ${String(e?.message || e)}`)))
    if (!res.ok) {
      return { success: false, error: `HTTP ${res.status}` }
    }
    const data = await res.json()
    return { success: true, data }
  })

  // WebShare: 通过 API 列表接口拉取指定 provider 的池
  // 文档参考: https://apidocs.webshare.io/proxy-list/list
  ipcMain.handle('proxy:webshare:pull-list', async (_e, { provider_id }: { provider_id: string }) => {
    const cfg = getConfig()
    const providers = Array.isArray(cfg.proxy?.providers) ? cfg.proxy.providers : []
    const p = providers.find(pp => pp && (pp.id === provider_id)) as any
    if (!p)
      return { success: false, error: `provider ${provider_id} not found` }
    if (!p.api_key)
      return { success: false, error: 'missing api_key' }

    // 按类型选择 mode
    const mode = (String(p.type || '').toLowerCase() === 'residential') ? 'backbone' : 'direct'
    const qs: string[] = [`mode=${mode}`, 'page_size=200']
    if (p.plan_id)
      qs.push(`plan_id=${encodeURIComponent(String(p.plan_id))}`)
    let nextUrl: string | null = `https://proxy.webshare.io/api/v2/proxy/list/?${qs.join('&')}`
    const pool_all: string[] = []
    // 记录接口返回的统一用户名/密码（若提供）
    let apiUsername: string | undefined
    let apiPassword: string | undefined
    const cfgUsername = (p.auth && p.auth.username) ? String(p.auth.username) : ''
    const cfgPassword = (p.auth && p.auth.password) ? String(p.auth.password) : ''
    const authHeader: Record<string, string> = { Authorization: `Token ${p.api_key}` }

    // 构建免费代理候选（不依赖 enabled）
    function buildFreeProxyCandidates(): Array<{ server: string, auth?: { username: string, password: string } }> {
      const out: Array<{ server: string, auth?: { username: string, password: string } }> = []
      try {
        const all = Array.isArray(cfg.proxy?.providers) ? (cfg.proxy?.providers as any[]) : []
        const freeProviders = all.filter((it: any) => it && String(it.vendor || '').toLowerCase() === 'webshare' && it.is_free === true)
        for (const fp of freeProviders) {
          const pProto = fp.protocol || 'http'
          const fallback = (fp.auth && fp.auth.username) ? fp.auth : undefined
          const pool = Array.isArray(fp.pool) ? fp.pool : []
          for (const entry of pool) {
            const parts = String(entry || '').split(':')
            if (parts.length >= 2) {
              const host = parts[0]
              const port = parts[1]
              out.push({ server: `${pProto}://${host}:${port}`, auth: fallback })
            }
          }
        }
        for (let i = out.length - 1; i > 0; i--) {
          const j = Math.floor(Math.random() * (i + 1))
          const t = out[i]; out[i] = out[j]; out[j] = t
        }
      }
      catch {}
      return out
    }

    // 分页抓取：直连失败时，使用免费代理出站重试
    while (nextUrl) {
      let data: any
      try {
        const res = await fetch(nextUrl, { headers: authHeader })
        if (!res.ok)
          throw new Error(`HTTP ${res.status}`)
        data = await res.json()
      }
      catch (directErr: any) {
        // 通过免费代理重试
        const candidates = buildFreeProxyCandidates()
        let success = false
        let lastErr: any = directErr
        for (const c of candidates) {
          try {
            const text = await fetchTextThroughHttpProxy(nextUrl, c.server, c.auth, authHeader)
            data = JSON.parse(text)
            success = true
            break
          }
          catch (e: any) {
            lastErr = e
          }
        }
        if (!success)
          return { success: false, error: `WebShare list 请求失败: ${String(lastErr?.message || lastErr || directErr)}` }
      }
      const results = Array.isArray(data?.results) ? data.results : []
      for (const it of results) {
        const ip = String(it?.proxy_address || '').trim()
        const port = String(it?.port || '').trim()
        if (ip && port) {
          // 捕获接口返回的凭据（若一致则可用于 provider.auth）
          try {
            if (apiUsername === undefined && it && it.username)
              apiUsername = String(it.username)
            if (apiPassword === undefined && it && it.password)
              apiPassword = String(it.password)
          }
          catch {}
          const useUser = apiUsername || cfgUsername
          const usePass = apiPassword || cfgPassword
          if (useUser || usePass)
            pool_all.push(`${ip}:${port}:${useUser || ''}:${usePass || ''}`)
          else pool_all.push(`${ip}:${port}`)
        }
      }
      nextUrl = data?.next || null
    }

    // 应用规模限制与抽样
    const maxPerProvider = Math.max(1, Number(cfg.proxy?.max_active_pool_per_provider || 500))
    let selected: string[]
    if (pool_all.length <= maxPerProvider) {
      selected = pool_all
    }
    else {
      // 洗牌后截断，确保均匀抽样
      const arr = pool_all.slice()
      for (let i = arr.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1))
        const t = arr[i]
        arr[i] = arr[j]
        arr[j] = t
      }
      selected = arr.slice(0, maxPerProvider)
    }

    const pool: string[] = selected
    const pool_full: string[] | undefined = cfg.proxy?.save_full_pool ? pool_all : undefined

    // 更新该 provider 的 pool（保留其他字段）
    const nextProviders = providers.map((it) => {
      if (it && it.id === provider_id) {
        const nextAuth = (() => {
          // 若接口提供统一凭据，则回填到 provider.auth；否则保持原值
          if (apiUsername || apiPassword)
            return { username: String(apiUsername || ''), password: String(apiPassword || '') }
          return it.auth
        })()
        return { ...it, auth: nextAuth, pool, pool_full, pool_total: pool_all.length, pool_refreshed_at: Date.now() }
      }
      return it
    })

    await updateConfig({ proxy: { providers: nextProviders as any } as any })
    logger.info('✅ WebShare 列表拉取完成', { providerId: provider_id, count: pool.length })
    return { success: true, count: pool.length }
  })

  // 代理测试：对指定URL做HEAD检查，并通过同一代理获取出口IP信息
  ipcMain.handle('proxy:test-url', async (_e, { url, provider_id }: { url: string, provider_id?: string }) => {
    const cfg = getConfig()
    const entries = buildProxyEntries(cfg)
    if (!Array.isArray(entries) || entries.length === 0)
      return { success: false, error: '代理未启用或代理池为空' }

    // 可选按 provider 过滤
    const candidates = provider_id
      ? entries.filter(e => e.providerId === provider_id)
      : entries
    if (candidates.length === 0)
      return { success: false, error: `未找到指定 provider 的代理: ${provider_id}` }

    // 随机化候选并限制尝试数量
    const shuffled = candidates.slice()
    for (let i = shuffled.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1))
      const t = shuffled[i]; shuffled[i] = shuffled[j]; shuffled[j] = t
    }
    const maxTry = Math.min(10, shuffled.length)
    const attempts: any[] = []
    let lastError: any

    for (let i = 0; i < maxTry; i++) {
      const entry = shuffled[i]
      const username = entry.auth?.username
      const password = entry.auth?.password
      const providers = Array.isArray(cfg.proxy?.providers) ? cfg.proxy.providers : []
      const pInfo = entry.providerId && entry.providerId !== 'top'
        ? (providers.find((p: any) => p && p.id === entry.providerId) as any)
        : undefined
      const providerLabel = entry.providerId === 'top' ? 'Top Pool' : (pInfo?.label || entry.providerId || '')

      // 针对常见配置错误：若 server 为 https://ip:port，尝试 http:// 变体
      const variants = [entry.server]
      if (/^https:\/\//i.test(entry.server))
        variants.push(entry.server.replace(/^https:/i, 'http:'))

      for (const server of variants) {
        try {
          const status = await fetchHeadStatusThroughProxy(url, server, username, password, 12000)
          // 出口IP
          let ipAddress: string | undefined
          let ipRaw: string | undefined
          let ipSource: string | undefined
          const ipEchoUrls = ['https://api.ipify.org?format=json', 'https://ifconfig.me/ip']
          for (const u of ipEchoUrls) {
            try {
              const text = await fetchTextThroughHttpProxy(u, server, entry.auth)
              ipRaw = text
              ipSource = u
              try {
                const obj = JSON.parse(text)
                if (obj && obj.ip)
                  ipAddress = String(obj.ip)
              }
              catch {
                const plain = String(text || '').trim()
                if (/^\d+\.\d+\.\d+\.\d+$/.test(plain))
                  ipAddress = plain
              }
              if (ipAddress)
                break
            }
            catch {}
          }
          return {
            success: true,
            proxy: { server, provider_id: entry.providerId, provider_label: providerLabel, auth_username: username || undefined },
            test: { url, status },
            ip: { address: ipAddress, raw: ipRaw, source: ipSource },
            tried: attempts,
          }
        }
        catch (e: any) {
          lastError = e
          attempts.push({ server, error: String(e?.message || e) })
        }
      }
    }

    return { success: false, error: `连通性失败: ${String(lastError?.message || lastError || '未知错误')}`, tried: attempts }
  })
}

/**
 * 构建代理条目
 *
 * @description 构建代理条目，包括服务器、认证信息、提供商ID
 *
 * @param {AppConfig} cfg - 配置
 * @returns {Array<{ server: string, auth?: { username: string, password: string }, providerId?: string }>} 代理条目
 */
function buildProxyEntries(cfg: AppConfig): Array<{ server: string, auth?: { username: string, password: string }, providerId?: string }> {
  const items: Array<{ server: string, auth?: { username: string, password: string }, providerId?: string }> = []
  const providers = Array.isArray(cfg.proxy?.providers) ? cfg.proxy.providers : []
  for (const p of providers) {
    if (!p || p.enabled === false)
      continue
    const pProto = (p as any)?.protocol || 'http'
    const pAuth = (p as any)?.auth && (p as any).auth.username ? (p as any).auth : undefined
    const pPool = Array.isArray((p as any).pool) ? (p as any).pool : []
    for (const entry of pPool) {
      const { server, auth } = parseProxyEntry(entry, pAuth as any, pProto)
      items.push({ server, auth, providerId: (p as any).id })
    }
  }
  return items
}

async function validateSingle(server: string, username?: string, password?: string, validation?: AppConfig['proxy']['validation']): Promise<{ ok: boolean, status?: number, error?: string }> {
  const testUrl = validation?.test_url || 'https://www.gov.hk/'
  const timeout = Math.max(3000, (validation?.timeout_seconds ?? 10) * 1000)
  const expect = validation?.expect_status || 200
  try {
    const status = await fetchHeadStatusThroughProxy(testUrl, server, username, password, timeout)
    const ok = !!status && status === expect
    return { ok, status, error: ok ? undefined : `unexpected:${status}` }
  }
  catch (e: any) {
    return { ok: false, error: String(e?.message || e) }
  }
}

// 已移除下载专用出站代理(fetchViaProxyCandidatesHttp)逻辑，统一直连外部API

// 通过 HTTP 代理请求文本（支持 Basic 认证）
async function fetchTextThroughHttpProxy(targetUrl: string, proxyServer: string, auth?: { username: string, password: string }, extraHeaders?: Record<string, string>): Promise<string> {
  const HttpsProxyAgent = (await import('https-proxy-agent')).HttpsProxyAgent
  const httpMod = await import('node:http')
  const httpsMod = await import('node:https')
  const { Buffer: NodeBuffer } = await import('node:buffer')
  const cred = auth ? `${encodeURIComponent(auth.username)}:${encodeURIComponent(auth.password)}@` : ''
  const agent = new HttpsProxyAgent(proxyServer.replace('://', `://${cred}`))
  const url = new URL(targetUrl)
  const isHttps = url.protocol === 'https:'
  const options: any = {
    hostname: url.hostname,
    port: url.port || (isHttps ? 443 : 80),
    path: `${url.pathname}${url.search}`,
    method: 'GET',
    agent,
    headers: {
      'User-Agent': 'curl/8.4.0',
      'Accept': '*/*',
      'Connection': 'close',
      'Host': url.hostname,
    },
    timeout: 15000,
  }
  if (extraHeaders && typeof extraHeaders === 'object') {
    options.headers = { ...(options.headers || {}), ...extraHeaders }
  }
  return await new Promise<string>((resolve, reject) => {
    const req = (isHttps ? httpsMod.request : httpMod.request)(options, (res: any) => {
      if (res.statusCode && res.statusCode >= 400) {
        reject(new Error(`HTTP ${res.statusCode}`))
        return
      }
      const chunks: any[] = []
      res.on('data', (c: any) => chunks.push(c))
      res.on('end', () => resolve(NodeBuffer.concat(chunks).toString('utf8')))
    })
    req.on('timeout', () => req.destroy(new Error('ETIMEDOUT')))
    req.on('error', reject)
    req.end()
  })
}

// 通过代理仅获取状态码（HEAD 请求）
async function fetchHeadStatusThroughProxy(targetUrl: string, proxyServer: string, username?: string, password?: string, timeoutMs?: number): Promise<number> {
  const HttpsProxyAgent = (await import('https-proxy-agent')).HttpsProxyAgent
  const httpMod = await import('node:http')
  const httpsMod = await import('node:https')
  const url = new URL(targetUrl)
  const cred = username ? `${encodeURIComponent(username)}:${encodeURIComponent(password || '')}@` : ''
  const agent = new HttpsProxyAgent(proxyServer.replace('://', `://${cred}`))
  const isHttps = url.protocol === 'https:'
  const options: any = {
    hostname: url.hostname,
    port: url.port || (isHttps ? 443 : 80),
    path: `${url.pathname}${url.search}`,
    method: 'HEAD',
    agent,
    headers: {
      'User-Agent': 'curl/8.4.0',
      'Accept': '*/*',
      'Connection': 'close',
      'Host': url.hostname,
    },
    timeout: Math.max(2000, timeoutMs || 10000),
  }
  return await new Promise<number>((resolve, reject) => {
    const req = (isHttps ? httpsMod.request : httpMod.request)(options, (res: any) => {
      resolve(Number(res.statusCode || 0))
    })
    req.on('timeout', () => req.destroy(new Error('ETIMEDOUT')))
    req.on('error', reject)
    req.end()
  })
}
